package com.ax.framework.jfinal.server

import cn.hutool.core.io.resource.ClassPathResource
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONArray
import com.alibaba.fastjson.JSONObject
import com.alibaba.fastjson.JSONPath
import com.ax.framework.jfinal.directive.FileToStrDirective
import com.jfinal.server.undertow.PropExt
import com.jfinal.template.Engine
import com.jfinal.template.Template
import org.yaml.snakeyaml.Yaml
import java.io.InputStream
import java.util.*


/**
 *
 *  自定义的Prop对象
 *
 *  fastjson 可以 findByPath, PropExt自带的 getXXX不怎么好使, prop只能读取一层键值对
 *
 *  PropKit提供的几个方法, 都必须提供配置文件才能初始化 , 并添加到PropKit.map
 *
 *
 * @author 张天笑
 * @time 2018/11/27 19:56
 *
 */

class AppPropExt : PropExt {

    lateinit var json_object: JSONObject

    constructor(file_name: String) {
        properties = Properties()
        try {
            //从classpath加载配置文件
            var base_config_yaml_stream = ClassPathResource(file_name).stream
            val base_config_yaml_stream_string = resolveYmlTpl(base_config_yaml_stream)
            val yaml_content = Yaml().load<Any>(base_config_yaml_stream_string)
            val json_string = JSON.toJSONString(yaml_content)
            json_object = JSON.parseObject(json_string)
        } catch (e: Exception) {
            println("配置文件不存在于classpath, 请确认!")
            System.exit(0)
        }
    }

    constructor(file_name: String, json_object: JSONObject) {
        properties = Properties()
        this.json_object = json_object
    }


    override fun getBoolean(key: String): Boolean? = get(key)?.toBoolean()
    override fun getInt(key: String): Int? = get(key)?.toInt()
    override fun getLong(key: String): Long? = get(key)?.toLong()


    override fun getBoolean(key: String, default: Boolean?): Boolean = getBoolean(key) ?: default ?: false
    override fun getInt(key: String, default: Int): Int = getInt(key) ?: default
    override fun getLong(key: String, default: Long): Long = getLong(key) ?: default


    override fun get(key: String) = _get(key)?.toString()
    override fun get(key: String, default: String) = if (get(key) == null) default else get(key)

    /**
     * 自定义的_get方法
     * 没辙, super.get返回值写死了string类型
     * 在需要的时候强转回来调_get
     *
     * @author 张天笑
     * @time 2018/11/27 20:03
     *
     */
    fun _get(key: String): Any? {
        //尝试从properties中获取
        val get = properties.getProperty(key)
        if (get == null) {
            //尝试从json_Object中获取
            val string = json_object.getString(key)
            if (string == null) {
                //尝试通过json_path获取
                val eval = JSONPath.eval(json_object, key)
                if (eval != null) {
                    properties.put(key, eval)
                }

            } else {
                properties.put(key, string)
            }
        } else {
            properties.put(key, get)
        }
        return properties.get(key)
    }

    fun getArray(key: String): JSONArray? {
        return json_object.getJSONArray(key)
    }

    fun getDevMode(): Boolean {
        return getBoolean("undertow.dev_mode", false)
    }

    private fun resolveYmlTpl(stream: InputStream): String {
        val engine = Engine.use("app") ?: Engine.create("app")
        engine.removeDirective("file_to_str").addDirective("file_to_str", FileToStrDirective::class.java)

        var string = stream.reader().readText()

        //参数
        val map = hashMapOf<Any, Any>()
        var tpl: Template

        //
        while (string.contains("#[^ ]+\\(.+\\)".toRegex())) {
            tpl = engine.getTemplateByString(string)
            string = tpl.renderToString(map)
        }
        return string
    }

}
